package com.logistics.pick.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.google.gson.Gson;
import com.logistics.dictionary.entity.model.DictionaryRow;
import com.logistics.dictionary.service.DictionaryService;
import com.logistics.erp.entity.domain.ErpInvbill;
import com.logistics.erp.entity.domain.ErpPlanQty;
import com.logistics.erp.service.ErpInvBillService;
import com.logistics.erp.service.ErpOrderService;
import com.logistics.map.entity.domain.MapComponents;
import com.logistics.map.entity.model.ComponentsEventRow;
import com.logistics.map.service.MapComponentsService;
import com.logistics.material.entity.model.MaterialBackRow;
import com.logistics.pick.entity.domain.*;
import com.logistics.pick.entity.model.PickInfoRow;
import com.logistics.pick.entity.model.PickQuery;
import com.logistics.pick.entity.model.PickRow;
import com.logistics.pick.entity.model.PickSave;
import com.logistics.pick.mapper.PickMapper;
import com.logistics.rcs.entity.model.RcsCoordinateRow;
import com.logistics.rcs.service.RcsService;
import com.logistics.utils.aspect.annotation.Insert;
import com.logistics.utils.aspect.annotation.Pager;
import com.logistics.utils.bean.ResultPager;
import com.logistics.utils.bean.TabFilter;
import com.logistics.utils.bean.UserBean;
import com.logistics.utils.constants.Constants;
import com.logistics.utils.constants.Message;
import com.logistics.utils.exception.MessageException;
import com.logistics.utils.message.Manager;
import com.logistics.utils.socket.EventData;
import com.logistics.utils.socket.MenConns;
import com.logistics.utils.tool.StringUtils;
import com.logistics.utils.tool.UserUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class PickService extends ServiceImpl<PickMapper, Pick> {

    @Autowired
    private PickMapper pickMapper;

    @Autowired
    private PickContainerService pickContainerService;

    @Autowired
    private ErpOrderService erpOrderService;

    @Autowired
    private ErpInvBillService erpInvBillService;

    @Autowired
    private PickDetailService pickDetailService;

    @Autowired
    private UserUtils userUtils;

    @Autowired
    private DictionaryService dictionaryService;

    @Autowired
    private MapComponentsService mapComponentsService;

    @Autowired
    private RcsService rcsService;


    private static Gson gson = new Gson();

    /**
     * 根据托盘编号查找托盘信息
     *
     * @param containerCode
     * @return
     */
    public Pick getPickContainer(String containerCode, String code) {
        if (StringUtils.isNotNull(code)) {
            return this.getOne(new LambdaQueryWrapper<Pick>().eq(Pick::getCode, code));
        } else if (StringUtils.isNotNull(containerCode)) {
            return pickMapper.findPickByContainer(containerCode);
        }
        return null;
    }

    /**
     * 查找托盘信息
     *
     * @param pickId
     * @return
     */
    public List<PickContainer> getPickContainerList(Integer pickId) {
        return pickMapper.findContainers(pickId);
    }

    /**
     * 根据id的拣配单
     * @param id
     * @return
     */
    public PickRow getPickOrderById(String id) throws MessageException {
        UserBean userBean = userUtils.getUserInfo();
        Pick pick = this.getOne(new LambdaQueryWrapper<Pick>().eq(Pick::getId, id));
        if(StringUtils.isNull(pick)){
            throw new MessageException("拣配单不存在");
        }
        boolean isShow = true;
        if(StringUtils.isEquals(userBean.getErpDeptCode(), Constants.WC_CODE_ASSEMBLE)){
            Integer count = pickDetailService.findAssemblyByBillNo(pick.getId());
            isShow = count > 0;
        }
        return PickRow.build(pick.getCode(), pick.getStatus(), pick.getId(), getPickContainerList(pick.getId()),isShow);
    }

    /**
     * 查询总数量
     * @param billNo
     * @param orderNo
     * @param itemCode
     * @param itemOpNo
     * @return
     */
//    public BigDecimal totalQty(String billNo, String orderNo, String itemCode, String itemOpNo){
//        Map<String, Object> params = new HashMap<>();
//        params.put("billNo", billNo);
//        params.put("orderNo", orderNo);
//        params.put("itemCode", itemCode);
//        params.put("itemOpNo", itemOpNo);
//        return pickMapper.findTotalPickQty(params);
//    }

    /**
     * 完成拣配
     * @param params
     * @return
     */
    @Insert
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public void finishPick(PickSave params) throws MessageException {
        if (StringUtils.isNull(params.getId())) {
            throw new MessageException(Manager.getMessage(Message.MSG1005.getCode()));
        }
//        List<PickContainer> pickContainers = pickContainerService.list(new LambdaQueryWrapper<PickContainer>()
//                .eq(PickContainer::getPick, params.getId())
//                .and(i -> i.eq(PickContainer::getStation, "").or().isNull(PickContainer::getStation)));
        List<PickContainer> pickContainers = pickContainerService.list(new LambdaQueryWrapper<PickContainer>()
                .eq(PickContainer::getPick, params.getId()));
        // 查找物料信息
        List<PickDetail> pickDetailRows = pickDetailService.list(new LambdaQueryWrapper<PickDetail>()
                .eq(PickDetail::getPick, params.getId()));
        if(pickDetailRows.isEmpty()){
            throw new MessageException("没有拣配物料");
        }
        // 是否绑定站点
        boolean isBindLocation = pickContainers.stream().anyMatch(e -> StringUtils.isNotNull(e.getStation()));
        if (isBindLocation) {
            // 查找拣配单信息
            List<String> containers = pickDetailRows.stream().map(PickDetail::getContainer).distinct().collect(Collectors.toList());
            List<PickDetailInvBill> pickDetailInvBills = pickDetailService.materials(PickDetailInvBill.build(containers));
            List<String> invBillCodes = pickDetailInvBills.stream().map(PickDetailInvBill::getErpInvBillCode).distinct().collect(Collectors.toList());
            // 更新拣配托盘里的状态
            pickContainerService.update(PickContainer.build(Integer.parseInt(Constants.PICK_STATE_SUCCESS),
                    params.getCreator()), new LambdaQueryWrapper<PickContainer>()
                    .eq(PickContainer::getPick, params.getId()));
            // 每个托盘都有站点
            this.update(Pick.build(Constants.PICK_STATE_SUCCESS), new LambdaQueryWrapper<Pick>().eq(Pick::getId, params.getId()));
            if(StringUtils.isEquals(pickDetailInvBills.get(0).getErpInvBillType(), Constants.PICK_TYPE_NOT_CUBE)){
                // 非立体库逻辑
                List<PickQty> pickQty = pickDetailService.pickQtyGroupBySeq(params.getId());
                pickQty.forEach(item -> {
                    erpOrderService.updateOrderDetailPickQty(item.getSumQty(), item.getItemSeqNo());
                });
                List<String> seqNos = pickQty.stream().map(PickQty::getItemSeqNo).collect(Collectors.toList());
                erpOrderService.updateOrderDetailPickStatus(seqNos);
            } else if (StringUtils.isEquals(pickDetailInvBills.get(0).getErpInvBillType(), Constants.PICK_TYPE_PAINTING)) {//涂装拣配
                // 查找不缺料的领料单号
                List<PickQty> pickQty = pickDetailService.pickQty(params.getId());

                pickQty.forEach(pickItem -> {
                    erpOrderService.updatePickQty(pickItem.getSumQty(), pickItem.getErpInvBillCode(), pickItem.getItemCode());
                    erpOrderService.updatePickStatus(pickItem.getErpInvBillCode(), pickItem.getItemCode());
                });
            } else{ // 立体库逻辑
                // 查找计划数量
                Map<String, BigDecimal> planQtyMaps = erpOrderService.planQty(invBillCodes).
                        stream().collect(Collectors.toMap(ErpPlanQty::getInvBillCode, ErpPlanQty::getPlanQty));
                // 查找不缺料的领料单号
                List<PickQty> pickQty = pickDetailService.pickQty(params.getId());
                List<String> lackInvBillCodes = pickQty.stream().filter(item -> planQtyMaps.containsKey(item.getErpInvBillCode())
                                && planQtyMaps.get(item.getErpInvBillCode()).compareTo(item.getSumQty()) > 0).
                        map(PickQty::getErpInvBillCode).distinct().collect(Collectors.toList());
                if(!lackInvBillCodes.isEmpty()){
                    erpInvBillService.update(ErpInvbill.build(Constants.LACK_MATERIAL_STATUS_YES),
                            new LambdaQueryWrapper<ErpInvbill>().in(ErpInvbill::getErpInvbillCode, lackInvBillCodes));
                }
                pickQty.forEach(pickItem -> {
                    erpOrderService.updatePickQty(pickItem.getSumQty(), pickItem.getErpInvBillCode(),
                            pickItem.getItemWorkCode(), pickItem.getItemCode(), pickItem.getItemOpNo());
                });
                erpOrderService.updatePickStatus(invBillCodes);
            }
//            Map<String, Boolean> result = new HashMap<>();
//            result.put("isShow", true);
//            if(StringUtils.isEquals(userBean.getErpDeptCode(), Constants.WC_CODE_ASSEMBLE)){
//                Integer count = pickDetailService.findAssemblyByBillNo(invBillCodes);
//                result.put("isShow", count > 0);
//            }
            // 拣配完成发送消息到前端
//            pushFinishPick(pickContainers, containers);
//            return result;
        } else {
            throw new MessageException(Manager.getMessage(Message.MSG1024.getCode()));
        }
    }

    /**
     * 根据拣配单更新拣配单状态
     * @param pickId
     */
    public void updateStatusByPickId(String pickId, String status){
        Pick pick = this.getOne(new LambdaQueryWrapper<Pick>().eq(Pick::getId, pickId));
        if(StringUtils.isNotNull(pick)){
            // 更加ID回写拣配单状态
            this.update(Pick.build(status), new LambdaQueryWrapper<Pick>().eq(Pick::getId, pickId));
        }
    }

    /**
     * 查找拣配单班组信息和拣配单信息
     * @param wcCode
     * @param area
     * @return
     */
    public List<PickWorkshop> pickByWcCodeAndArea(String wcCode, String area) {
        Map<String, Object> params = new HashMap<>();
        params.put("wcCode", wcCode);
        params.put("area", area);
        return pickMapper.findByWcCodeAndArea(params);
    }

    /**
     * 根据查询条件(拣配单号，erp单据号，状态)  分页 查找拣配单信息
     * @param params
     * @return
     */
    @Pager
    public ResultPager getPickInfoByFilter(PickQuery params) throws MessageException {
        //获取分页信息
        IPage page = new Page(params.getCurrent(), params.getPageSize());
        params.setPage((int) page.offset());
        //查询数据
        List<PickAndErpInvbill> pickInfoList = pickMapper.findPickInfoByFilter(params);
        //查询数据总条数
        params.setPageSize(0);
        long pickInfoCount = pickMapper.findPickInfoByFilter(params).stream().count();
        //返回拣配单信息
        return new ResultPager(pickInfoList.stream().map(item -> PickInfoRow.build(item))
                .collect(Collectors.toList()), (int) pickInfoCount);
    }

    /**
     * 获取拣配单状态filter信息
     * @param
     * @return
     */
    public List<TabFilter> getPickStatusFilter() throws MessageException {
        List<DictionaryRow> deliveryTypeList = dictionaryService.getChildrenByCode("pick_status_type");
        List<TabFilter> filterList = new ArrayList<>();
        filterList.add(TabFilter
                .unLimitFilter("全部"));
        deliveryTypeList.forEach(e ->
                filterList.add(TabFilter
                        .build(e.getName(), e.getCode(), Constants.TABFILTER_TYPE_CHECKBOX,  e.getCode())));
        return filterList;
    }

    /**
     * 推送拣配完成的物料到前端
     * @param pickContainers
     * @param containers
     * @throws MessageException
     */
    private void pushFinishPick(List<PickContainer> pickContainers, List<String> containers) throws MessageException {
        // 过滤出所有站点
        List<String> stations = pickContainers.stream().map(PickContainer::getStation).collect(Collectors.toList());
        // 查找站点
        Map<String, List<MapComponents>> locationMaps = mapComponentsService.list(new LambdaQueryWrapper<MapComponents>().
                in(MapComponents::getLocation, stations)).stream().collect(Collectors.groupingBy(MapComponents::getLocation));
        // 查找物料
        Map<String, List<PickDetail>> materialMaps = pickDetailService.list(new LambdaQueryWrapper<PickDetail>()
                .in(PickDetail::getContainer, containers)).stream().collect(Collectors.groupingBy(PickDetail::getContainer));
        Map<String, RcsCoordinateRow> coordinateMaps = rcsService.coordinateRows(stations.stream().map(item -> item.split("-")[1])
                .collect(Collectors.toList())).stream().
                collect(Collectors.toMap(RcsCoordinateRow::getPoint, coordinateRow -> coordinateRow));
        List<ComponentsEventRow> data = pickContainers.stream().map(item -> {
            MapComponents location = locationMaps.get(item.getStation()).get(0);
            ComponentsEventRow row = ComponentsEventRow.build(item.getContainer(),
                    location, materialMaps.get(item.getContainer()));
            String key = location.getLocation().split("-")[1];
            if(StringUtils.isNotNull(coordinateMaps.get(key))){
                row.setX(coordinateMaps.get(key).getX());
                row.setY(coordinateMaps.get(key).getY());
            }
            return row;
        }).collect(Collectors.toList());
        MenConns.sendText("__pick_finish", data);
    }
}
